<template>
  <div class="container">
    <div class="app-container">
      <div class="left">
        <el-input
          v-model.trim="queryParams.keyword"
          style="margin-bottom:10px"
          type="text"
          prefix-icon="el-icon-search"
          size="small"
          placeholder="输入员工姓名全员搜索"
          @input="onKeyWordInput"
        />
        <!-- 树形组件 -->
        <!-- node-key="id" 意思是把节点数据中的 id 的值，作为当前节点的 key ，这里定义的时候不需要冒号 -->
        <el-tree
          ref="tree"
          :data="treeNodes"
          :props="defaultProps"
          default-expand-all
          highlight-current
          node-key="id"
          :expand-on-click-node="false"
          @node-click="onNodeClick"
        />
      </div>
      <div class="right">
        <el-row class="opeate-tools" type="flex" justify="end">
          <el-button v-perm="'add-employee'" size="mini" type="primary" @click="$router.push('/employee/detail')">添加员工</el-button>
          <el-button size="mini" @click="showImportDialog = true">excel导入</el-button>
          <el-button size="mini" @click="exportUserListAsExcel">excel导出</el-button>
        </el-row>
        <!-- 表格组件 -->
        <el-table v-loading="loading" :data="userList">
          <el-table-column align="center" label="头像" prop="staffPhoto">
            <template v-slot="{ row }">
              <UserAvatar :avatar="row.staffPhoto" :backup="row.username" :size="30" />
            </template>
          </el-table-column>
          <el-table-column label="姓名" prop="username" />
          <el-table-column label="手机号" sortable prop="mobile" />
          <el-table-column label="工号" sortable prop="workNumber" />
          <el-table-column label="聘用形式" prop="formOfEmployment">
            <template v-slot="{ row }">
              {{ staffType(row.formOfEmployment) }}
            </template>
          </el-table-column>
          <el-table-column label="部门" prop="departmentName" />
          <el-table-column label="入职时间" sortable prop="timeOfEntry" />
          <el-table-column label="操作" width="280px">
            <template v-slot="{ row }">
              <el-button size="mini" type="text" @click="$router.push(`/employee/detail/${row.id}`)">查看</el-button>
              <el-button size="mini" type="text" @click="showAssignRoleDialog(row.id)">角色</el-button>
              <el-popconfirm title="确认要删除这个用户吗？" @onConfirm="deleteUser(row.id)">
                <el-button slot="reference" type="text">删除</el-button>
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页 -->
        <el-row style="height: 60px" align="middle" type="flex" justify="end">
          <el-pagination
            layout="total,prev, pager, next"
            :total="total"
            :current-page="queryParams.page"
            @current-change="onPageChange"
          />
        </el-row>
      </div>
    </div>
    <ImportExcel :show-excel-dialog.sync="showImportDialog" @done="showUserList" />
    <!-- 定义一个弹框：给员工分配角色 -->
    <el-dialog title="分配角色" :visible.sync="showRoleDialog">
      <el-checkbox-group v-model="roleIds">
        <el-checkbox v-for="role in roleList" :key="role.id" :label="role.id">{{ role.name }}</el-checkbox>
      </el-checkbox-group>
      <el-row slot="footer" type="flex" justify="center">
        <el-col :span="6">
          <el-button type="primary" size="mini" @click="btnRoleOK">确定</el-button>
          <el-button size="mini" @click="showRoleDialog = false">取消</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script>
import UserAvatar from '@/layout/components/UserAvatar.vue'
import { getDepartments } from '@/api/department'
import { translateListToTree } from '@/utils/index'
import { getUserListPaged, exportUserList, deleteEmployee, getUserInfo, assignRole } from '@/api/employee'
import { getEnabledRoleList } from '@/api/role'
import { saveAs } from 'file-saver'
import ImportExcel from './components/import-excel.vue'

export default {
  name: 'Employee',
  components: {
    UserAvatar,
    ImportExcel
  },
  data() {
    return {
      loading: false,
      // 控制是否显示导入弹框组件
      showImportDialog: false,
      treeNodes: [],
      defaultProps: {
        // 节点字段到数据字段的映射
        label: 'name',
        children: 'children'
      },
      // 定义获取员工的请求对象
      queryParams: {
        page: 1,
        pagesize: 10,
        keyword: '',
        departmentId: 0
      },
      userList: [],
      // 员工总数
      total: 0,
      timer: null,
      // 是否显示分配角色弹框
      showRoleDialog: false,
      roleIds: [], // 员工选中了哪些角色
      roleList: [] // 可选的角色列表
    }
  },
  created() {
    this.getDepartmentList()
  },
  methods: {
    async getDepartmentList() {
      const res = await getDepartments()
      // this.treeNodes = res
      // 从 res 中找到所有 pid 为 0 的项
      // 最终：treeNodes 中只有 pid 为 0 的项
      this.treeNodes = translateListToTree(res, 0)
      // 逻辑关注点：把一个需求的逻辑封闭在一个区间内（区间可以是函数，也可以代码块）
      // 拿到部门列表数据以后，默认讲第一个（索引为 0）的 id 设置为当前的 id
      // 注意：这里直接赋值不会生效，为什么？因为组件的渲染时异步的，这里的赋值时同步的，所以会先赋值，再渲染
      // 如何解决：
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(res[0].id)
        // 有没有根据选中的第0项去调接口：没有
        // 所以要做这件事情: 其实就是模拟一下节点的点击
        this.onNodeClick({ id: res[0].id })
      })
    },
    showUserList() {
      this.loading = true
      getUserListPaged(this.queryParams)
        .then(res => {
          this.userList = res.rows
          this.total = res.total
          this.loading = false
        })
    },
    // 处理节点被点击的方法
    onNodeClick(data) {
      // 节点被点击，说明是切换部门
      // 既然是切换部门，那么用户的列表数据就应该第一页开始获取
      this.queryParams.page = 1
      // console.log(data)
      // 请求员工列表的对象就组装完成了
      // 记录节点Id
      this.queryParams.departmentId = data.id
      // 获取员工数据
      this.showUserList()
    },
    staffType(typeValue) {
      // typeValue 是一个 枚举值
      switch (typeValue) {
        case 1: return '正式'
        case 2: return '非正式'
        default: return '其他'
      }
    },
    onPageChange(page) {
      // 1. 修改查询的参数
      this.queryParams.page = page
      // console.log(page)
      // 2. 获取当前页的用户列表
      // 获取员工数据
      this.showUserList()
    },
    // 处理搜索框的输入事件
    onKeyWordInput() {
      // 搜索框防抖处理：
      // 通过clearTimeout 和下面的 setTimerout 最终实现的效果是什么：只有一个函数函数在执行
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        // console.log(this.queryParams.keyword)
        // 根据关键词，再去调接口，获取用户的列表
        // 注意：当前页码应该是多少？1
        this.queryParams.page = 1
        // 其余的参数：部门id 不动 pagesize 也不动 keyword是要变化
        // 获取员工数据
        this.showUserList()
      }, 1000)
    },
    exportUserListAsExcel() {
      // console.log('执行导出')
      // 执行导出的逻辑
      // 1. 调接口 （返回的是二进制的文件流 ==> axios内部，需要将二进制流转成 blob 对象）
      // 2. 把返回的数据（blob对象）保存为一个excel文件
      // 结论：1. 要处理二进制文件流，需要Blob对象 2. 要保存文件也需要blob对象
      exportUserList().then(blob => {
        console.log(blob)
        // 保存文件：需要一个blob对象
        saveAs(blob, '员工列表.xlsx')
      })
    },
    // 删除用户
    deleteUser(id) {
      deleteEmployee(id).then(() => {
        this.$message.success('用户删除成功')
        if (this.userList.length === 1 && this.queryParams.page > 1) {
          this.queryParams.page--
        }
        this.showUserList()
      })
    },
    // 显示分配角色弹框的：回显用户当前的角色
    async showAssignRoleDialog(id) {
      // 这个用户id在 data 中定义或者不定义都可以
      // 思考：
      // 1. 为什么？==> 模板中用不到，不需要
      // 2. 此时的 employeeId 是响应式的吗？不是响应式
      this.employeeId = id

      // 1. 先获取员工的角色信息（调获取员工基本信息的接口，得到 roleIds） ==> getUserInfo
      // 2. 获取当前可分配的角色列表 ==> getEnabledRoleList
      // 3. 显示弹框，回显数据
      // const { roleIds } = await getUserInfo(id) // 300ms
      // this.roleIds = roleIds
      // const roles = await getEnabledRoleList() // 400ms
      // this.roleList = roles
      // // 显示弹框
      // this.showRoleDialog = true

      // 补充和优化：
      // Promise.all() 的使用场景是什么：
      // 1. 没有顺序的请求，请求之间不依赖返回值
      // Promise.all(参数) 参数是什么：数组 ==> 是一个 Promise 对象组成的数组
      // 但是 有些时候 数组里面可以不是 Promise，可以直接就是一个简单的值，比如 对象 数组 ...
      // 此时 Promise 的内部会把这些 非Promise 的值转变成 Promise 对象
      // 回到案例：获取员工角色信息 和 获取可选角色列表这两个接口之间没有依赖关系
      // 所以可以并发请求，节省时间
      const arr = [getUserInfo(id), getEnabledRoleList()]
      Promise.all(arr).then(res => {
        // res是什么？？是一个结果组成的数组，顺序与原数组一一对应
        this.roleIds = res[0].roleIds
        this.roleList = res[1]
        this.showRoleDialog = true
      })
    },
    // 更新员工的角色 ==> 给员工分配角色
    btnRoleOK() {
      assignRole({
        id: this.employeeId, // 员工的id
        roleIds: this.roleIds
      })
        .then(() => {
          this.$message.success('分配角色成功')
          this.showRoleDialog = false
        })
    }
  }
}
</script>

<style lang="scss" scoped>
.app-container {
  background: #fff;
  display: flex;
  .left {
    width: 280px;
    padding: 20px;
    border-right: 1px solid #eaeef4;
  }
  .right {
    flex: 1;
    padding: 20px;
    .opeate-tools {
      margin:10px ;
    }
    .username {
      height: 30px;
      width: 30px;
      line-height: 30px;
      text-align: center;
      border-radius: 50%;
      color: #fff;
      background: #04C9BE;
      font-size: 12px;
      display:inline-block;
    }
  }
}

</style>
